package com.godenwater.recv.server.summit;


import cn.gov.mwr.sl651.utils.ByteUtil;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;

/**
 * Created by Li on 2017/3/30.
 * 字段名	字节数	说明
 * 起始字符	1	固定0x68
 * 长度L	1	为用户数据区的字节数
 * 起始字符	1	固定0x68
 * 用户数据区	L	详见用户数据格式
 * CRC校验	1	CRC8多项式X7+X6+X5+X2+1，为用户数据区的CRC8校验，详见附件代码
 * 结束字符	1	固定0x16
 * <p>
 * <p>
 * 用户数据区格式：
 * 字段名	字节数	说明
 * 数据类型	1	水位数据0xB5 雨量数据0xBB 流量数据0xB6，（数据类型字段雨量为0xBE、水位为0xBD）
 * 行政区划	2	BCD码，0x12 0x34则表示行政区划为1234
 * 终端机站号	2	16进制，低字节在前，0x15 0x03表示站号为789
 * 预留字节	1	固定0x40
 * 数据来源	1	定时上报0x80 阈值加报0x86 历史记录查询0x84
 * 传感器序号	1	多种同类传感器的区分编号，从0x01开始
 * 测量数据	N	详见测量数据格式
 * 预留字节	2	固定0x00 0x00
 * 时间标签	6	BCD码的秒分时日月年00 31 10 12 03 12，表示12年3月
 * 12日10点31分0秒
 * 设备温度（℃）	3	BCD码，为当前设备温度+1000℃（为了应对零下温度数据），43 24 10为1024.43，表示+24.43℃
 * 供电电压（V）	2	BCD码，36 12表示RTU供电电压12.36V
 * 充电电压（V）	2	BCD码，12 13 表示太阳能充电电压13.12V
 * 设备故障码	2	16进制，每位表示不同的设备故障，00 00 表示无故障
 */
public class SummitParser {
    public static SummitMessage96 parse96(byte[] buffer) {
        SummitMessage96 summitMessage96 = new SummitMessage96();
        return null;
    }

    public static SummitMessage parse(byte[] buffer) {
        SummitMessage message = new SummitMessage();

        int pos = 1;//去掉第一个字节
        int len = buffer.length;

        byte[] blen = new byte[1];
        System.arraycopy(buffer, pos, blen, 0, blen.length);
        //message.setStcd(stcd);
        pos = pos + blen.length;
        pos = pos + 1;//多加后面一个字节

        byte[] dtype = new byte[1];//水位数据0xB5 雨量数据0xBB 流量数据0xB6
        System.arraycopy(buffer, pos, dtype, 0, dtype.length);
        message.setType(dtype[0]);
        pos = pos + dtype.length;

        byte[] addvcd = new byte[2];//行政区划	2BCD
        System.arraycopy(buffer, pos, addvcd, 0, addvcd.length);
        //message.setStcd(stcd);
        pos = pos + addvcd.length;

        byte[] rtucd = new byte[2];//终端机站号	2
        System.arraycopy(buffer, pos, rtucd, 0, rtucd.length);
        message.setStcd("" + ByteUtil.bytesToShort(new byte[]{rtucd[1], rtucd[0]}));
        pos = pos + rtucd.length;
        pos = pos + 1;

        byte[] afn = new byte[1];//AFN定时上报0x80 阈值加报0x86 历史记录查询0x84
        System.arraycopy(buffer, pos, afn, 0, afn.length);
        message.setFunccode(afn[0]);
        pos = pos + afn.length;

        byte[] sensor = new byte[1];//A
        System.arraycopy(buffer, pos, sensor, 0, sensor.length);
        //message.setStcd(stcd);
        pos = pos + sensor.length;

        //水位数据0xB5 雨量数据0xBB 流量数据0xB6
        int nbodyLen = parseDataLen((byte) dtype[0], afn[0]);
        if (nbodyLen == 0) {
            return null;
        }

        byte[] nbody = new byte[nbodyLen];
        System.arraycopy(buffer, pos, nbody, 0, nbody.length);
        //message.setStcd(stcd);
        message.setContent(nbody);
        pos = pos + nbody.length;
        pos = pos + 2;//保留字节

        byte[] viewdate = new byte[6];// 时间
        System.arraycopy(buffer, pos, viewdate, 0, viewdate.length);
        message.setViewdate(parseDate(new byte[]{viewdate[5], viewdate[4], viewdate[3], viewdate[2], viewdate[1], viewdate[0]}));
        pos = pos + viewdate.length;

        byte[] tempature = new byte[3];//设备温度（℃）	3	BCD码，为当前设备温度+1000℃（为了应对零下温度数据），43 24 10为1024.43，表示+24.43℃
        System.arraycopy(buffer, pos, tempature, 0, tempature.length);
        message.setTempature(parseTemperature(new byte[]{tempature[2], tempature[1], tempature[0]}));
        pos = pos + tempature.length;

        byte[] voltage1 = new byte[2];//供电电压（V）	2	BCD码，36 12表示RTU供电电压12.36V
        System.arraycopy(buffer, pos, voltage1, 0, voltage1.length);
        message.setVoltage1(ByteUtil.bcd2Str(new byte[]{voltage1[1], voltage1[0]}));
        pos = pos + voltage1.length;

        byte[] voltage2 = new byte[2];//充电电压（V）	2	BCD码，12 13 表示太阳能充电电压13.12V
        System.arraycopy(buffer, pos, voltage2, 0, voltage2.length);
        message.setVoltage2(ByteUtil.bcd2Str(new byte[]{voltage2[1], voltage2[0]}));
        pos = pos + voltage2.length;

        byte[] err = new byte[2];//设备故障码	2	16进制，每位表示不同的设备故障，00 00 表示无故障
        System.arraycopy(buffer, pos, err, 0, err.length);
        message.setErr(ByteUtil.bytesToUshort(new byte[]{err[1], err[0]}));
        pos = pos + err.length;

        byte[] crc = new byte[1];//CRC
        System.arraycopy(buffer, pos, crc, 0, crc.length);
        //message.setStcd(stcd);
        pos = pos + crc.length;

        byte[] eof = new byte[1];//eof
        System.arraycopy(buffer, pos, eof, 0, eof.length);
        //message.setStcd(stcd);
        pos = pos + eof.length;

        return message;
    }

    /**
     * 根据报文的类型和报文上报模式决定数据的长度
     * 根据定时报、加报报的类型来决定后面字节的长度，
     * 水位定时报，后面有28个字节（4个基值，24个水位）
     * 雨量定时报，后面有24个字节
     * 水位加报报，后面有3个字节
     * 雨量加报报，后面有7个字节
     *
     * @param type
     * @param mode
     * @return
     */
    public static int parseDataLen(byte type, byte mode) {
        //定时上报0x80 阈值加报0x86 历史记录查询0x84
        int nbodyLen = 0;
        //定时报
        if (mode == (byte) 0x80) {
            switch (type) {
                case (byte) 0xB5://水位长度为3
                case (byte) 0xBD://水位长度为3
                    nbodyLen = 28;
                    break;
                case (byte) 0xBB://雨量长度为7
                case (byte) 0xBE://雨量长度为7
                    nbodyLen = 24;
                    break;
                case (byte) 0xB6://这个不清楚
                    nbodyLen = 24;
                    break;
            }
        }

        //加报报
        if (mode == (byte) 0x86) {
            switch (type) {
                case (byte) 0xB5://水位长度为3
                case (byte) 0xBD://水位长度为3
                    nbodyLen = 3;
                    break;
                case (byte) 0xBB://雨量长度为7
                case (byte) 0xBE://雨量长度为7
                    nbodyLen = 7;
                    break;
                case (byte) 0xB6://流量长度为6
                    nbodyLen = 6;
                    break;
            }
        }

        return nbodyLen;
    }

    /**
     * 解析一小时雨量值
     *
     * @param rain
     * @return
     */
    public static int[] parseRain(byte[] rain) {
        int[] rv = new int[12];
        int pos = 0;
        for (int i = 0; i < 12; i++) {
            byte[] bv = new byte[2];
            System.arraycopy(rain, pos, bv, 0, 2);
            int value = ByteUtil.bytesToUshort(new byte[]{bv[1], bv[0]});
            rv[i] = value;
            pos = pos + 2;
        }
        return rv;
    }

    /**
     * 解析一小时水位
     *
     * @param river
     * @return
     */
    public static int[] parseRiver(byte[] river) {
        int[] rv = new int[12];
        int pos = 4;
        for (int i = 0; i < 12; i++) {
            byte[] bv = new byte[2];
            System.arraycopy(river, pos, bv, 0, 2);
            int value = ByteUtil.bytesToUshort(new byte[]{bv[1], bv[0]});
            rv[i] = value;

            pos = pos + 2;
        }
        return rv;
    }

    public static float[] parseBcdRiver(byte[] river) {
        float[] rv = new float[12];
        int pos = 4;
        for (int i = 0; i < 12; i++) {
            byte[] bv = new byte[2];
            System.arraycopy(river, pos, bv, 0, 2);

            String value = ByteUtil.bcd2Str(new byte[]{bv[1], bv[0]});
            rv[i] = Float.valueOf(value) / 100 - 1000;
            ;
            pos = pos + 2;
        }
        return rv;
    }

    public static String parseDate(byte[] data) {
        String value = ByteUtil.bcd2Str(data);
        return value;
    }

    public static double parseTemperature(byte[] data) {
        String value = ByteUtil.bcd2Str(data);
        BigDecimal b1 = new BigDecimal(value);
        BigDecimal b2 = new BigDecimal(1000);
        b1 = b1.divide(new BigDecimal(100));
        return b1.subtract(b2).doubleValue();
    }

    //BCD码，为测量到的水位+1000米，（为了应对地下负水位状况），45 23 11为1123.45，表示水位+123.45米
    public static float parseRiverValue(byte[] data) {
        String value = ByteUtil.bcd2Str(data);
        return Float.valueOf(value) / 100 - 1000;
    }

    //转换基值
    public static float parseRiverBaseValue(byte[] data) {
        byte[] rv = new byte[4];
        System.arraycopy(data, 0, rv, 0, 4);
        int value = ByteUtil.bytesToInt(new byte[]{rv[3], rv[2], rv[1], rv[0]});
        return (Float.valueOf(value) / 100);//- 1000
    }

    public static void main(String[] args) {
        String msg = "68 20 68 BB 12 34 15 03 40 80 01 15 02 00 00 15 00 00 00 00 00 07 15 12 03 12 43 24 10 36 12 00 00 70 00 6B 16";
        msg = StringUtils.replace(msg, " ", "");

        msg = "680d68b342136400408e13872854174fb916";

        SummitParser parser = new SummitParser();

        byte[] aa = new byte[]{0x12, 0x34};
        int value = ByteUtil.bytesToUshort(aa);
        System.out.println(value);

        parser.parse(ByteUtil.HexStringToBinary(msg));

    }

}
